//
// typemanager.cs: C# type manager
//
// Author: Miguel de Icaza (miguel@gnu.org)
//         Ravi Pratap     (ravi@ximian.com)
//         Marek Safar     (marek.safar@gmail.com)
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
// Copyright 2003-2011 Novell, Inc.
// Copyright 2011 Xamarin Inc
//

using System;
using System.Globalization;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Teal.Compiler
{
	//
	// All compiler built-in types (they have to exist otherwise the compiler will not work)
	//
	public class BuiltinTypes
	{
		public readonly BuiltinTypeSpec Object;
		public readonly BuiltinTypeSpec ValueType;
		public readonly BuiltinTypeSpec Attribute;

		public readonly BuiltinTypeSpec Int;
		public readonly BuiltinTypeSpec UInt;
		public readonly BuiltinTypeSpec Long;
		public readonly BuiltinTypeSpec ULong;
		public readonly BuiltinTypeSpec Float;
		public readonly BuiltinTypeSpec Double;
		public readonly BuiltinTypeSpec Char;
		public readonly BuiltinTypeSpec Short;
		public readonly BuiltinTypeSpec Decimal;
		public readonly BuiltinTypeSpec Bool;
		public readonly BuiltinTypeSpec SByte;
		public readonly BuiltinTypeSpec Byte;
		public readonly BuiltinTypeSpec UShort;
		public readonly BuiltinTypeSpec String;

		public readonly BuiltinTypeSpec Enum;
		public readonly BuiltinTypeSpec Delegate;
		public readonly BuiltinTypeSpec MulticastDelegate;
		public readonly BuiltinTypeSpec Void;
		public readonly BuiltinTypeSpec Array;
		public readonly BuiltinTypeSpec Type;
		public readonly BuiltinTypeSpec IEnumerator;
		public readonly BuiltinTypeSpec IEnumerable;
		public readonly BuiltinTypeSpec IDisposable;
		public readonly BuiltinTypeSpec IntPtr;
		public readonly BuiltinTypeSpec UIntPtr;
		public readonly BuiltinTypeSpec RuntimeFieldHandle;
		public readonly BuiltinTypeSpec RuntimeTypeHandle;
		public readonly BuiltinTypeSpec Exception;

		//
		// These are internal buil-in types which depend on other
		// build-in type (mostly object)
		//
		public readonly BuiltinTypeSpec Dynamic;

		// Predefined operators tables
		public readonly BinaryExpression.PredefinedOperator[] OperatorsBinaryStandard;
		public readonly BinaryExpression.PredefinedOperator[] OperatorsBinaryEquality;
		public readonly BinaryExpression.PredefinedOperator[] OperatorsBinaryUnsafe;
		public readonly TypeReference[][] OperatorsUnary;
		public readonly TypeReference[] OperatorsUnaryMutator;

		public readonly TypeReference[] BinaryPromotionsTypes;

		readonly BuiltinTypeSpec[] types;

		public BuiltinTypes ()
		{
			Object = new BuiltinTypeSpec (MemberKind.Class, "System", "Object", BuiltinTypeSpec.Type.Object);
			ValueType = new BuiltinTypeSpec (MemberKind.Class, "System", "ValueType", BuiltinTypeSpec.Type.ValueType);
			Attribute = new BuiltinTypeSpec (MemberKind.Class, "System", "Attribute", BuiltinTypeSpec.Type.Attribute);

			Int = new BuiltinTypeSpec (MemberKind.Struct, "System", "Int32", BuiltinTypeSpec.Type.Int);
			Long = new BuiltinTypeSpec (MemberKind.Struct, "System", "Int64", BuiltinTypeSpec.Type.Long);
			UInt = new BuiltinTypeSpec (MemberKind.Struct, "System", "UInt32", BuiltinTypeSpec.Type.UInt);
			ULong = new BuiltinTypeSpec (MemberKind.Struct, "System", "UInt64", BuiltinTypeSpec.Type.ULong);
			Byte = new BuiltinTypeSpec (MemberKind.Struct, "System", "Byte", BuiltinTypeSpec.Type.Byte);
			SByte = new BuiltinTypeSpec (MemberKind.Struct, "System", "SByte", BuiltinTypeSpec.Type.SByte);
			Short = new BuiltinTypeSpec (MemberKind.Struct, "System", "Int16", BuiltinTypeSpec.Type.Short);
			UShort = new BuiltinTypeSpec (MemberKind.Struct, "System", "UInt16", BuiltinTypeSpec.Type.UShort);

			IEnumerator = new BuiltinTypeSpec (MemberKind.Interface, "System.Collections", "IEnumerator", BuiltinTypeSpec.Type.IEnumerator);
			IEnumerable = new BuiltinTypeSpec (MemberKind.Interface, "System.Collections", "IEnumerable", BuiltinTypeSpec.Type.IEnumerable);
			IDisposable = new BuiltinTypeSpec (MemberKind.Interface, "System", "IDisposable", BuiltinTypeSpec.Type.IDisposable);

			Char = new BuiltinTypeSpec (MemberKind.Struct, "System", "Char", BuiltinTypeSpec.Type.Char);
			String = new BuiltinTypeSpec (MemberKind.Class, "System", "String", BuiltinTypeSpec.Type.String);
			Float = new BuiltinTypeSpec (MemberKind.Struct, "System", "Single", BuiltinTypeSpec.Type.Float);
			Double = new BuiltinTypeSpec (MemberKind.Struct, "System", "Double", BuiltinTypeSpec.Type.Double);
			Decimal = new BuiltinTypeSpec (MemberKind.Struct, "System", "Decimal", BuiltinTypeSpec.Type.Decimal);
			Bool = new BuiltinTypeSpec (MemberKind.Struct, "System", "Boolean", BuiltinTypeSpec.Type.Bool);
			IntPtr = new BuiltinTypeSpec (MemberKind.Struct, "System", "IntPtr", BuiltinTypeSpec.Type.IntPtr);
			UIntPtr = new BuiltinTypeSpec (MemberKind.Struct, "System", "UIntPtr", BuiltinTypeSpec.Type.UIntPtr);

			MulticastDelegate = new BuiltinTypeSpec (MemberKind.Class, "System", "MulticastDelegate", BuiltinTypeSpec.Type.MulticastDelegate);
			Delegate = new BuiltinTypeSpec (MemberKind.Class, "System", "Delegate", BuiltinTypeSpec.Type.Delegate);
			Enum = new BuiltinTypeSpec (MemberKind.Class, "System", "Enum", BuiltinTypeSpec.Type.Enum);
			Array = new BuiltinTypeSpec (MemberKind.Class, "System", "Array", BuiltinTypeSpec.Type.Array);
			Void = new BuiltinTypeSpec (MemberKind.Void, "System", "Void", BuiltinTypeSpec.Type.Other);
			Type = new BuiltinTypeSpec (MemberKind.Class, "System", "Type", BuiltinTypeSpec.Type.Type);
			Exception = new BuiltinTypeSpec (MemberKind.Class, "System", "Exception", BuiltinTypeSpec.Type.Exception);
			RuntimeFieldHandle = new BuiltinTypeSpec (MemberKind.Struct, "System", "RuntimeFieldHandle", BuiltinTypeSpec.Type.Other);
			RuntimeTypeHandle = new BuiltinTypeSpec (MemberKind.Struct, "System", "RuntimeTypeHandle", BuiltinTypeSpec.Type.Other);

			// TODO: Maybe I should promote it to different kind for faster compares
			Dynamic = new BuiltinTypeSpec ("dynamic", BuiltinTypeSpec.Type.Dynamic);

			OperatorsBinaryStandard = BinaryExpression.CreateStandardOperatorsTable (this);
			OperatorsBinaryEquality = BinaryExpression.CreateEqualityOperatorsTable (this);
			OperatorsBinaryUnsafe = BinaryExpression.CreatePointerOperatorsTable (this);
			OperatorsUnary = UnaryExpression.CreatePredefinedOperatorsTable (this);
			OperatorsUnaryMutator = UnaryMutatorExpression.CreatePredefinedOperatorsTable (this);

			BinaryPromotionsTypes = ConstantFold.CreateBinaryPromotionsTypes (this);

			types = new BuiltinTypeSpec[] {
				Object, ValueType, Attribute,
				Int, UInt, Long, ULong, Float, Double, Char, Short, Decimal, Bool, SByte, Byte, UShort, String,
				Enum, Delegate, MulticastDelegate, Void, Array, Type, IEnumerator, IEnumerable, IDisposable,
				IntPtr, UIntPtr, RuntimeFieldHandle, RuntimeTypeHandle, Exception };
		}

		public bool CheckDefinitions (ModuleDefinition module)
		{ 
			foreach (var p in types) {
				var found = PredefinedType.Resolve (module, p.Kind, p.Namespace, p.name, p.genericParameterCount, true, true);
				if (found == null || found == p)
					continue;

                //var tc = found.MemberDefinition2 as TypeDefinition;
                //if (tc != null) {
                //    var ns = module.GlobalRootNamespace.GetNamespace (p.Namespace, false);
                //    ns.SetBuiltinType (p);

                //    tc.SetPredefinedSpec (p);
                //    p.SetDefinition (found);
                //}
			}

			if (Compiler.errorCount != 0)
				return false;

			// Set internal build-in types
			Dynamic.SetDefinition (Object);

			return true;
		}
	}

	//
	// Compiler predefined types. Usually used for compiler generated
	// code or for comparison against well known framework type. They
	// may not exist as they are optional
	//
	class PredefinedTypes2
	{
		public readonly PredefinedType ArgIterator;
		public readonly PredefinedType TypedReference;
		public readonly PredefinedType MarshalByRefObject;
		public readonly PredefinedType RuntimeHelpers;
		public readonly PredefinedType IAsyncResult;
		public readonly PredefinedType AsyncCallback;
		public readonly PredefinedType RuntimeArgumentHandle;
		public readonly PredefinedType CharSet;
		public readonly PredefinedType IsVolatile;
		public readonly PredefinedType IEnumeratorGeneric;
		public readonly PredefinedType IListGeneric;
		public readonly PredefinedType IReadOnlyListGeneric;
		public readonly PredefinedType ICollectionGeneric;
		public readonly PredefinedType IReadOnlyCollectionGeneric;
		public readonly PredefinedType IEnumerableGeneric;
		public readonly PredefinedType Nullable;
		public readonly PredefinedType Activator;
		public readonly PredefinedType Interlocked;
		public readonly PredefinedType Monitor;
		public readonly PredefinedType NotSupportedException;
		public readonly PredefinedType RuntimeFieldHandle;
		public readonly PredefinedType RuntimeMethodHandle;
		public readonly PredefinedType SecurityAction;
		public readonly PredefinedType Dictionary;
		public readonly PredefinedType Hashtable;
		public readonly TypeReference[] SwitchUserTypes;

		//
		// C# 3.0
		//
		public readonly PredefinedType Expression;
		public readonly PredefinedType ExpressionGeneric;
		public readonly PredefinedType ParameterExpression;
		public readonly PredefinedType FieldInfo;
		public readonly PredefinedType MethodBase;
		public readonly PredefinedType MethodInfo;
		public readonly PredefinedType ConstructorInfo;
		public readonly PredefinedType MemberBinding;

		//
		// C# 4.0
		//
		public readonly PredefinedType Binder;
		public readonly PredefinedType CallSite;
		public readonly PredefinedType CallSiteGeneric;
		public readonly PredefinedType BinderFlags;

		//
		// C# 5.0
		//
		public readonly PredefinedType AsyncVoidMethodBuilder;
		public readonly PredefinedType AsyncTaskMethodBuilder;
		public readonly PredefinedType AsyncTaskMethodBuilderGeneric;
		public readonly PredefinedType Action;
		public readonly PredefinedType Task;
		public readonly PredefinedType TaskGeneric;
		public readonly PredefinedType IAsyncStateMachine;
		public readonly PredefinedType INotifyCompletion;
		public readonly PredefinedType ICriticalNotifyCompletion;

		public PredefinedTypes2 (ModuleDefinition module)
		{
			TypedReference = new PredefinedType (module, MemberKind.Struct, "System", "TypedReference");
			ArgIterator = new PredefinedType (module, MemberKind.Struct, "System", "ArgIterator");

			MarshalByRefObject = new PredefinedType (module, MemberKind.Class, "System", "MarshalByRefObject");
			RuntimeHelpers = new PredefinedType (module, MemberKind.Class, "System.Runtime.CompilerServices", "RuntimeHelpers");
			IAsyncResult = new PredefinedType (module, MemberKind.Interface, "System", "IAsyncResult");
			AsyncCallback = new PredefinedType (module, MemberKind.Delegate, "System", "AsyncCallback");
			RuntimeArgumentHandle = new PredefinedType (module, MemberKind.Struct, "System", "RuntimeArgumentHandle");
			CharSet = new PredefinedType (module, MemberKind.Enum, "System.Runtime.InteropServices", "CharSet");
			IsVolatile = new PredefinedType (module, MemberKind.Class, "System.Runtime.CompilerServices", "IsVolatile");
			IEnumeratorGeneric = new PredefinedType (module, MemberKind.Interface, "System.Collections.Generic", "IEnumerator", 1);
			IListGeneric = new PredefinedType (module, MemberKind.Interface, "System.Collections.Generic", "IList", 1);
			IReadOnlyListGeneric = new PredefinedType (module, MemberKind.Interface, "System.Collections.Generic", "IReadOnlyList", 1);
			ICollectionGeneric = new PredefinedType (module, MemberKind.Interface, "System.Collections.Generic", "ICollection", 1);
			IReadOnlyCollectionGeneric = new PredefinedType (module, MemberKind.Interface, "System.Collections.Generic", "IReadOnlyCollection", 1);
			IEnumerableGeneric = new PredefinedType (module, MemberKind.Interface, "System.Collections.Generic", "IEnumerable", 1);
			Nullable = new PredefinedType (module, MemberKind.Struct, "System", "Nullable", 1);
			Activator = new PredefinedType (module, MemberKind.Class, "System", "Activator");
			Interlocked = new PredefinedType (module, MemberKind.Class, "System.Threading", "Interlocked");
			Monitor = new PredefinedType (module, MemberKind.Class, "System.Threading", "Monitor");
			NotSupportedException = new PredefinedType (module, MemberKind.Class, "System", "NotSupportedException");
			RuntimeFieldHandle = new PredefinedType (module, MemberKind.Struct, "System", "RuntimeFieldHandle");
			RuntimeMethodHandle = new PredefinedType (module, MemberKind.Struct, "System", "RuntimeMethodHandle");
			SecurityAction = new PredefinedType (module, MemberKind.Enum, "System.Security.Permissions", "SecurityAction");
			Dictionary = new PredefinedType (module, MemberKind.Class, "System.Collections.Generic", "Dictionary", 2);
			Hashtable = new PredefinedType (module, MemberKind.Class, "System.Collections", "Hashtable");

			Expression = new PredefinedType (module, MemberKind.Class, "System.Linq.Expressions", "Expression");
			ExpressionGeneric = new PredefinedType (module, MemberKind.Class, "System.Linq.Expressions", "Expression", 1);
			MemberBinding = new PredefinedType (module, MemberKind.Class, "System.Linq.Expressions", "MemberBinding");
			ParameterExpression = new PredefinedType (module, MemberKind.Class, "System.Linq.Expressions", "ParameterExpression");
			FieldInfo = new PredefinedType (module, MemberKind.Class, "System.Reflection", "FieldInfo");
			MethodBase = new PredefinedType (module, MemberKind.Class, "System.Reflection", "MethodBase");
			MethodInfo = new PredefinedType (module, MemberKind.Class, "System.Reflection", "MethodInfo");
			ConstructorInfo = new PredefinedType (module, MemberKind.Class, "System.Reflection", "ConstructorInfo");

			CallSite = new PredefinedType (module, MemberKind.Class, "System.Runtime.CompilerServices", "CallSite");
			CallSiteGeneric = new PredefinedType (module, MemberKind.Class, "System.Runtime.CompilerServices", "CallSite", 1);
			Binder = new PredefinedType (module, MemberKind.Class, "Microsoft.CSharp.RuntimeBinder", "Binder");
			BinderFlags = new PredefinedType (module, MemberKind.Enum, "Microsoft.CSharp.RuntimeBinder", "CSharpBinderFlags");

			Action = new PredefinedType (module, MemberKind.Delegate, "System", "Action");
			AsyncVoidMethodBuilder = new PredefinedType (module, MemberKind.Struct, "System.Runtime.CompilerServices", "AsyncVoidMethodBuilder");
			AsyncTaskMethodBuilder = new PredefinedType (module, MemberKind.Struct, "System.Runtime.CompilerServices", "AsyncTaskMethodBuilder");
			AsyncTaskMethodBuilderGeneric = new PredefinedType (module, MemberKind.Struct, "System.Runtime.CompilerServices", "AsyncTaskMethodBuilder", 1);
			Task = new PredefinedType (module, MemberKind.Class, "System.Threading.Tasks", "Task");
			TaskGeneric = new PredefinedType (module, MemberKind.Class, "System.Threading.Tasks", "Task", 1);
			IAsyncStateMachine = new PredefinedType (module, MemberKind.Interface, "System.Runtime.CompilerServices", "IAsyncStateMachine");
			INotifyCompletion = new PredefinedType (module, MemberKind.Interface, "System.Runtime.CompilerServices", "INotifyCompletion");
			ICriticalNotifyCompletion = new PredefinedType (module, MemberKind.Interface, "System.Runtime.CompilerServices", "ICriticalNotifyCompletion");

			//
			// Define types which are used for comparison. It does not matter
			// if they don't exist as no error report is needed
			//
			if (TypedReference.Define ())
				TypedReference.TypeSpec.IsSpecialRuntimeType = true;

			if (ArgIterator.Define ())
				ArgIterator.TypeSpec.IsSpecialRuntimeType = true;

			if (IEnumerableGeneric.Define ())
				IEnumerableGeneric.TypeSpec.IsArrayGenericInterface = true;

			if (IListGeneric.Define ())
				IListGeneric.TypeSpec.IsArrayGenericInterface = true;

			if (IReadOnlyListGeneric.Define ())
				IReadOnlyListGeneric.TypeSpec.IsArrayGenericInterface = true;

			if (ICollectionGeneric.Define ())
				ICollectionGeneric.TypeSpec.IsArrayGenericInterface = true;

			if (IReadOnlyCollectionGeneric.Define ())
				IReadOnlyCollectionGeneric.TypeSpec.IsArrayGenericInterface = true;

			if (Nullable.Define ())
				Nullable.TypeSpec.IsNullableType = true;

			if (ExpressionGeneric.Define ())
				ExpressionGeneric.TypeSpec.IsExpressionTreeType = true;

			Task.Define ();
			if (TaskGeneric.Define ())
				TaskGeneric.TypeSpec.IsGenericTask = true;

			SwitchUserTypes = SwitchStatement.CreateSwitchUserTypes (module, Nullable.TypeSpec);
		}
	}

	class PredefinedMembers
	{
		public readonly PredefinedMember<MethodReference> ActivatorCreateInstance;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderCreate;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderStart;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderSetResult;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderSetException;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderSetStateMachine;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderOnCompleted;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderOnCompletedUnsafe;
		public readonly PredefinedMember<PropertyReference> AsyncTaskMethodBuilderTask;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderGenericCreate;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderGenericStart;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderGenericSetResult;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderGenericSetException;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderGenericSetStateMachine;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderGenericOnCompleted;
		public readonly PredefinedMember<MethodReference> AsyncTaskMethodBuilderGenericOnCompletedUnsafe;
		public readonly PredefinedMember<PropertyReference> AsyncTaskMethodBuilderGenericTask;
		public readonly PredefinedMember<MethodReference> AsyncVoidMethodBuilderCreate;
		public readonly PredefinedMember<MethodReference> AsyncVoidMethodBuilderStart;
		public readonly PredefinedMember<MethodReference> AsyncVoidMethodBuilderSetException;
		public readonly PredefinedMember<MethodReference> AsyncVoidMethodBuilderSetResult;
		public readonly PredefinedMember<MethodReference> AsyncVoidMethodBuilderSetStateMachine;
		public readonly PredefinedMember<MethodReference> AsyncVoidMethodBuilderOnCompleted;
		public readonly PredefinedMember<MethodReference> AsyncVoidMethodBuilderOnCompletedUnsafe;
		public readonly PredefinedMember<MethodReference> AsyncStateMachineAttributeCtor;
		public readonly PredefinedMember<MethodReference> DebuggerBrowsableAttributeCtor;
		public readonly PredefinedMember<MethodReference> DecimalCtor;
		public readonly PredefinedMember<MethodReference> DecimalCtorInt;
		public readonly PredefinedMember<MethodReference> DecimalCtorLong;
		public readonly PredefinedMember<MethodReference> DecimalConstantAttributeCtor;
		public readonly PredefinedMember<MethodReference> DefaultMemberAttributeCtor;
		public readonly PredefinedMember<MethodReference> DelegateCombine;
		public readonly PredefinedMember<MethodReference> DelegateEqual;
		public readonly PredefinedMember<MethodReference> DelegateInequal;
		public readonly PredefinedMember<MethodReference> DelegateRemove;
		public readonly PredefinedMember<MethodReference> DynamicAttributeCtor;
		public readonly PredefinedMember<MethodReference> FieldInfoGetFieldFromHandle;
		public readonly PredefinedMember<MethodReference> FieldInfoGetFieldFromHandle2;
		public readonly PredefinedMember<MethodReference> IDisposableDispose;
		public readonly PredefinedMember<MethodReference> IEnumerableGetEnumerator;
		public readonly PredefinedMember<MethodReference> InterlockedCompareExchange;
		public readonly PredefinedMember<MethodReference> InterlockedCompareExchange_T;
		public readonly PredefinedMember<MethodReference> FixedBufferAttributeCtor;
		public readonly PredefinedMember<MethodReference> MethodInfoGetMethodFromHandle;
		public readonly PredefinedMember<MethodReference> MethodInfoGetMethodFromHandle2;
		public readonly PredefinedMember<MethodReference> MonitorEnter;
		public readonly PredefinedMember<MethodReference> MonitorEnter_v4;
		public readonly PredefinedMember<MethodReference> MonitorExit;
		public readonly PredefinedMember<PropertyReference> RuntimeCompatibilityWrapNonExceptionThrows;
		public readonly PredefinedMember<MethodReference> RuntimeHelpersInitializeArray;
		public readonly PredefinedMember<PropertyReference> RuntimeHelpersOffsetToStringData;
		public readonly PredefinedMember<ConstSpec> SecurityActionRequestMinimum;
		public readonly PredefinedMember<FieldReference> StringEmpty;
		public readonly PredefinedMember<MethodReference> StringEqual;
		public readonly PredefinedMember<MethodReference> StringInequal;
		public readonly PredefinedMember<MethodReference> StructLayoutAttributeCtor;
		public readonly PredefinedMember<FieldReference> StructLayoutCharSet;
		public readonly PredefinedMember<FieldReference> StructLayoutSize;
		public readonly PredefinedMember<MethodReference> TypeGetTypeFromHandle;

		public PredefinedMembers (ModuleDefinition module)
		{
			var types = module.PredefinedTypes;
			var atypes = module.PredefinedAttributes;
			var btypes = Compiler.BuiltinTypes;

            var tp = new TypeParameter(0, new MemberName("T"), null, Variance.None);

            ActivatorCreateInstance = new PredefinedMember<MethodReference>(types.Activator, MemberFilter.Method("CreateInstance", 1, ParametersCompiled.EmptyReadOnlyParameters, null));

            AsyncTaskMethodBuilderCreate = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilder, MemberFilter.Method("Create", 0, ParametersCompiled.EmptyReadOnlyParameters, types.AsyncTaskMethodBuilder.TypeSpec));

            AsyncTaskMethodBuilderSetResult = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilder, MemberFilter.Method("SetResult", 0, ParametersCompiled.EmptyReadOnlyParameters, btypes.Void));

            AsyncTaskMethodBuilderSetStateMachine = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilder, "SetStateMachine", MemberKind.Method, () => new[] {
						types.IAsyncStateMachine.TypeSpec
				}, btypes.Void);

            AsyncTaskMethodBuilderSetException = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilder, MemberFilter.Method("SetException", 0,
                ParametersCompiled.CreateFullyResolved(btypes.Exception), btypes.Void));

            AsyncTaskMethodBuilderOnCompleted = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilder, MemberFilter.Method("AwaitOnCompleted", 2,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
								new ParameterData (null, Parameter2.Modifier.REF)
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
								new MemberReference.GenericParameter (1, tp, Variance.None, null)
							}, false),
                    btypes.Void));

            AsyncTaskMethodBuilderOnCompletedUnsafe = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilder, MemberFilter.Method("AwaitUnsafeOnCompleted", 2,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
								new ParameterData (null, Parameter2.Modifier.REF)
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
								new MemberReference.GenericParameter (1, tp, Variance.None, null)
							}, false),
                    btypes.Void));

            AsyncTaskMethodBuilderStart = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilder, MemberFilter.Method("Start", 1,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
							}, false),
                    btypes.Void));

            AsyncTaskMethodBuilderTask = new PredefinedMember<PropertyReference>(types.AsyncTaskMethodBuilder, MemberFilter.Property("Task", null));

            AsyncTaskMethodBuilderGenericCreate = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilderGeneric, MemberFilter.Method("Create", 0, ParametersCompiled.EmptyReadOnlyParameters, types.AsyncVoidMethodBuilder.TypeSpec));

            AsyncTaskMethodBuilderGenericSetResult = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilderGeneric, "SetResult", MemberKind.Method, () => new TypeReference[] {
						types.AsyncTaskMethodBuilderGeneric.TypeSpec.MemberDefinition2.TypeParameters[0]
				}, btypes.Void);

            AsyncTaskMethodBuilderGenericSetStateMachine = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilderGeneric, "SetStateMachine", MemberKind.Method, () => new[] {
						types.IAsyncStateMachine.TypeSpec
				}, btypes.Void);

            AsyncTaskMethodBuilderGenericSetException = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilderGeneric, MemberFilter.Method("SetException", 0,
                ParametersCompiled.CreateFullyResolved(btypes.Exception), btypes.Void));

            AsyncTaskMethodBuilderGenericOnCompleted = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilderGeneric, MemberFilter.Method("AwaitOnCompleted", 2,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
								new ParameterData (null, Parameter2.Modifier.REF)
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
								new MemberReference.GenericParameter (1, tp, Variance.None, null)
							}, false),
                    btypes.Void));

            AsyncTaskMethodBuilderGenericOnCompletedUnsafe = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilderGeneric, MemberFilter.Method("AwaitUnsafeOnCompleted", 2,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
								new ParameterData (null, Parameter2.Modifier.REF)
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
								new MemberReference.GenericParameter (1, tp, Variance.None, null)
							}, false),
                    btypes.Void));

            AsyncTaskMethodBuilderGenericStart = new PredefinedMember<MethodReference>(types.AsyncTaskMethodBuilderGeneric, MemberFilter.Method("Start", 1,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
							}, false),
                    btypes.Void));

            AsyncTaskMethodBuilderGenericTask = new PredefinedMember<PropertyReference>(types.AsyncTaskMethodBuilderGeneric, MemberFilter.Property("Task", null));

            AsyncVoidMethodBuilderCreate = new PredefinedMember<MethodReference>(types.AsyncVoidMethodBuilder, MemberFilter.Method("Create", 0, ParametersCompiled.EmptyReadOnlyParameters, types.AsyncVoidMethodBuilder.TypeSpec));

            AsyncVoidMethodBuilderSetException = new PredefinedMember<MethodReference>(types.AsyncVoidMethodBuilder, MemberFilter.Method("SetException", 0, null, btypes.Void));

            AsyncVoidMethodBuilderSetResult = new PredefinedMember<MethodReference>(types.AsyncVoidMethodBuilder, MemberFilter.Method("SetResult", 0, ParametersCompiled.EmptyReadOnlyParameters, btypes.Void));

            AsyncVoidMethodBuilderSetStateMachine = new PredefinedMember<MethodReference>(types.AsyncVoidMethodBuilder, "SetStateMachine", MemberKind.Method, () => new[] {
						types.IAsyncStateMachine.TypeSpec
				}, btypes.Void);

            AsyncVoidMethodBuilderOnCompleted = new PredefinedMember<MethodReference>(types.AsyncVoidMethodBuilder, MemberFilter.Method("AwaitOnCompleted", 2,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
								new ParameterData (null, Parameter2.Modifier.REF)
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
								new MemberReference.GenericParameter (1, tp, Variance.None, null)
							}, false),
                    btypes.Void));

            AsyncVoidMethodBuilderOnCompletedUnsafe = new PredefinedMember<MethodReference>(types.AsyncVoidMethodBuilder, MemberFilter.Method("AwaitUnsafeOnCompleted", 2,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
								new ParameterData (null, Parameter2.Modifier.REF)
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
								new MemberReference.GenericParameter (1, tp, Variance.None, null)
							}, false),
                    btypes.Void));

            AsyncVoidMethodBuilderStart = new PredefinedMember<MethodReference>(types.AsyncVoidMethodBuilder, MemberFilter.Method("Start", 1,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
							}, false),
                    btypes.Void));

            AsyncStateMachineAttributeCtor = new PredefinedMember<MethodReference>(atypes.AsyncStateMachine, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(
                    btypes.Type)));

            DebuggerBrowsableAttributeCtor = new PredefinedMember<MethodReference>(atypes.DebuggerBrowsable, MemberFilter.Constructor(null));

            DecimalCtor = new PredefinedMember<MethodReference>(btypes.Decimal, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(
                    btypes.Int, btypes.Int, btypes.Int, btypes.Bool, btypes.Byte)));

            DecimalCtorInt = new PredefinedMember<MethodReference>(btypes.Decimal, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(btypes.Int)));

            DecimalCtorLong = new PredefinedMember<MethodReference>(btypes.Decimal, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(btypes.Long)));

            DecimalConstantAttributeCtor = new PredefinedMember<MethodReference>(atypes.DecimalConstant, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(
                    btypes.Byte, btypes.Byte, btypes.UInt, btypes.UInt, btypes.UInt)));

            DefaultMemberAttributeCtor = new PredefinedMember<MethodReference>(atypes.DefaultMember, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(btypes.String)));

            DelegateCombine = new PredefinedMember<MethodReference>(btypes.Delegate, "Combine", btypes.Delegate, btypes.Delegate);
            DelegateRemove = new PredefinedMember<MethodReference>(btypes.Delegate, "Remove", btypes.Delegate, btypes.Delegate);

            DelegateEqual = new PredefinedMember<MethodReference>(btypes.Delegate, new MemberFilter(OperatorDefinition.GetMetadataName(OperatorDefinition.OpType.Equality), 0, MemberKind.Operator, null, btypes.Bool));

            DelegateInequal = new PredefinedMember<MethodReference>(btypes.Delegate, new MemberFilter(OperatorDefinition.GetMetadataName(OperatorDefinition.OpType.Inequality), 0, MemberKind.Operator, null, btypes.Bool));

            DynamicAttributeCtor = new PredefinedMember<MethodReference>(atypes.Dynamic, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(
                    ArrayContainer.MakeType(module, btypes.Bool))));

            FieldInfoGetFieldFromHandle = new PredefinedMember<MethodReference>(types.FieldInfo, "GetFieldFromHandle", MemberKind.Method, types.RuntimeFieldHandle);

            FieldInfoGetFieldFromHandle2 = new PredefinedMember<MethodReference>(types.FieldInfo, "GetFieldFromHandle", MemberKind.Method, types.RuntimeFieldHandle, new PredefinedType(btypes.RuntimeTypeHandle));

            FixedBufferAttributeCtor = new PredefinedMember<MethodReference>(atypes.FixedBuffer, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(btypes.Type, btypes.Int)));

            IDisposableDispose = new PredefinedMember<MethodReference>(btypes.IDisposable, "Dispose", TypeReference.EmptyTypes);

            IEnumerableGetEnumerator = new PredefinedMember<MethodReference>(btypes.IEnumerable, "GetEnumerator", TypeReference.EmptyTypes);

            InterlockedCompareExchange = new PredefinedMember<MethodReference>(types.Interlocked, MemberFilter.Method("CompareExchange", 0,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
								new ParameterData (null, Parameter2.Modifier.NONE),
								new ParameterData (null, Parameter2.Modifier.NONE)
							},
                        new[] {
								btypes.Int, btypes.Int, btypes.Int
							},
                        false),
                btypes.Int));

            InterlockedCompareExchange_T = new PredefinedMember<MethodReference>(types.Interlocked, MemberFilter.Method("CompareExchange", 1,
                    new ParametersImported(
                        new[] {
								new ParameterData (null, Parameter2.Modifier.REF),
								new ParameterData (null, Parameter2.Modifier.NONE),
								new ParameterData (null, Parameter2.Modifier.NONE)
							},
                        new[] {
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
								new MemberReference.GenericParameter (0, tp, Variance.None, null),
							}, false),
                    null));

            MethodInfoGetMethodFromHandle = new PredefinedMember<MethodReference>(types.MethodBase, "GetMethodFromHandle", MemberKind.Method, types.RuntimeMethodHandle);

            MethodInfoGetMethodFromHandle2 = new PredefinedMember<MethodReference>(types.MethodBase, "GetMethodFromHandle", MemberKind.Method, types.RuntimeMethodHandle, new PredefinedType(btypes.RuntimeTypeHandle));

            MonitorEnter = new PredefinedMember<MethodReference>(types.Monitor, "Enter", btypes.Object);

            MonitorEnter_v4 = new PredefinedMember<MethodReference>(types.Monitor, MemberFilter.Method("Enter", 0,
                    new ParametersImported(new[] {
							new ParameterData (null, Parameter2.Modifier.NONE),
							new ParameterData (null, Parameter2.Modifier.REF)
						},
                    new[] {
							btypes.Object, btypes.Bool
						}, false), null));

            MonitorExit = new PredefinedMember<MethodReference>(types.Monitor, "Exit", btypes.Object);

            RuntimeCompatibilityWrapNonExceptionThrows = new PredefinedMember<PropertyReference>(atypes.RuntimeCompatibility, MemberFilter.Property("WrapNonExceptionThrows", btypes.Bool));

            RuntimeHelpersInitializeArray = new PredefinedMember<MethodReference>(types.RuntimeHelpers, "InitializeArray", btypes.Array, btypes.RuntimeFieldHandle);

            RuntimeHelpersOffsetToStringData = new PredefinedMember<PropertyReference>(types.RuntimeHelpers, MemberFilter.Property("OffsetToStringData", btypes.Int));

            SecurityActionRequestMinimum = new PredefinedMember<ConstSpec>(types.SecurityAction, "RequestMinimum", MemberKind.Field, types.SecurityAction);

            StringEmpty = new PredefinedMember<FieldReference>(btypes.String, MemberFilter.Field("Empty", btypes.String));

            StringEqual = new PredefinedMember<MethodReference>(btypes.String, new MemberFilter(OperatorDefinition.GetMetadataName(OperatorDefinition.OpType.Equality), 0, MemberKind.Operator, null, btypes.Bool));

            StringInequal = new PredefinedMember<MethodReference>(btypes.String, new MemberFilter(OperatorDefinition.GetMetadataName(OperatorDefinition.OpType.Inequality), 0, MemberKind.Operator, null, btypes.Bool));

            StructLayoutAttributeCtor = new PredefinedMember<MethodReference>(atypes.StructLayout, MemberFilter.Constructor(ParametersCompiled.CreateFullyResolved(btypes.Short)));

            StructLayoutCharSet = new PredefinedMember<FieldReference>(atypes.StructLayout, "CharSet", MemberKind.Field, types.CharSet);

            StructLayoutSize = new PredefinedMember<FieldReference>(atypes.StructLayout, MemberFilter.Field("Size", btypes.Int));

            TypeGetTypeFromHandle = new PredefinedMember<MethodReference>(btypes.Type, "GetTypeFromHandle", btypes.RuntimeTypeHandle);
		}
	}

	public class PredefinedType
	{
		readonly string name;
		readonly string ns;
		readonly int arity;
		readonly MemberKind kind;
		protected readonly ModuleDefinition module;
		protected TypeReference type;
		bool defined;

		public PredefinedType (ModuleDefinition module, MemberKind kind, string ns, string name, int arity)
			: this (module, kind, ns, name)
		{
			this.arity = arity;
		}

		public PredefinedType (ModuleDefinition module, MemberKind kind, string ns, string name)
		{
			this.module = module;
			this.kind = kind;
			this.name = name;
			this.ns = ns;
		}

		public PredefinedType (BuiltinTypeSpec type)
		{
			this.kind = type.Kind;
			this.name = type.name;
			this.ns = type.Namespace;
			this.type = type;
		}

		#region Properties

		public int Arity {
			get {
				return arity;
			}
		}

		public bool IsDefined {
			get {
				return type != null;
			}
		}

		public string Name {
			get {
				return name;
			}
		}

		public string Namespace {
			get {
				return ns;
			}
		}

		public TypeReference TypeSpec {
			get {
				return type;
			}
		}

		#endregion

		public bool Define ()
		{
			if (type != null)
				return true;

			if (!defined) {
				defined = true;
				type = Resolve (module, kind, ns, name, arity, false, false);
			}

			return type != null;
		}

		public string GetSignatureForError ()
		{
			return ns + "." + name;
		}

		public static TypeReference Resolve (ModuleDefinition module, MemberKind kind, string ns, string name, int arity, bool required, bool reportErrors)
		{
			//
			// Cannot call it with true because it could create non-existent namespaces for
			// predefined types. It's set to true only for build-in types which all must
			// exist therefore it does not matter, for predefined types we don't want to create
			// fake namespaces when type is optional and does not exist (e.g. System.Linq).
			//
			//Namespace type_ns = module.GlobalRootNamespace.GetNamespace (ns, required);

			IList<TypeReference> found = null;
            //if (type_ns != null)
            //    found = type_ns.GetAllTypes (name);

			if (found == null) {
				if (reportErrors)
					Compiler.Report.Error (518, "The predefined type `{0}.{1}' is not defined or imported", ns, name);

				return null;
			}

			TypeReference best_match = null;
			foreach (var candidate in found) {
				if (candidate.Kind != kind) {
					if (candidate.Kind == MemberKind.Struct && kind == MemberKind.Void && candidate.MemberDefinition2 is MemberContainerDefinition) {
						// Void is declared as struct but we keep it internally as
						// special kind, the swap will be done by caller
					} else {
						continue;
					}
				}

				if (candidate.genericParameterCount != arity)
					continue;

				if (best_match == null) {
					best_match = candidate;
					continue;
				}

				var other_match = best_match;
				if (!best_match.MemberDefinition2.IsImported &&
					Compiler.BuiltinTypes.Object.MemberDefinition2.DeclaringAssembly == candidate.MemberDefinition2.DeclaringAssembly) {
					best_match = candidate;
				}

				string location;
				if (best_match.MemberDefinition2 is MemberDefinition) {
					location = ((MemberDefinition) best_match.MemberDefinition2).startLocation2.Name;
				} else {
				    location = "asdasd";
				}

				Compiler.Report.SymbolRelatedToPreviousError (other_match);
				Compiler.Report.SymbolRelatedToPreviousError (candidate);

				Compiler.Report.Warning (1685, 1,
					"The predefined type `{0}.{1}' is defined multiple times. Using definition from `{2}'",
					ns, name, location);

				break;
			}

			if (best_match == null && reportErrors) {
				var found_member = found[0];

				if (found_member.Kind == MemberKind.MissingType) {
					// CSC: should be different error number
					Compiler.Report.Error (518, "The predefined type `{0}.{1}' is defined in an assembly that is not referenced.", ns, name);
				} else {
					Location2 loc;
					if (found_member.MemberDefinition2 is MemberDefinition) {
						loc = ((MemberDefinition) found_member.MemberDefinition2).startLocation2;
					} else {
						loc = Location2.Null;
						Compiler.Report.SymbolRelatedToPreviousError (found_member);
					}

					Compiler.Report.Error (520, loc, "The predefined type `{0}.{1}' is not declared correctly", ns, name);
				}
			}

			return best_match;
		}

		public TypeReference Resolve ()
		{
			if (type == null)
				type = Resolve (module, kind, ns, name, arity, false, true);

			return type;
		}
	}

	public class PredefinedMember<T> where T : MemberReference
	{ 
		T member;
		TypeReference declaring_type;
		readonly PredefinedType declaring_type_predefined;
		MemberFilter filter;
		readonly Func<TypeReference[]> filter_builder;

        public PredefinedMember(PredefinedType type, MemberFilter filter)
		{ 
			this.declaring_type_predefined = type;
			this.filter = filter;
		}

        public PredefinedMember(TypeReference type, MemberFilter filter)
		{ 
			this.declaring_type = type;
			this.filter = filter;
		}

        public PredefinedMember(PredefinedType type, string name, params TypeReference[] types)
            : this(type, MemberFilter.Method(name, 0, ParametersCompiled.CreateFullyResolved(types), null))
		{
		}

        public PredefinedMember(PredefinedType type, string name, MemberKind kind, params PredefinedType[] types)
            : this(type, new MemberFilter(name, 0, kind, null, null))
		{
			filter_builder = () => {
				var ptypes = new TypeReference[types.Length];
				for (int i = 0; i < ptypes.Length; ++i) {
					var p = types[i];
					if (!p.Define ())
						return null;

					ptypes[i] = p.TypeSpec;
				}

				return ptypes;
			};
		}

        public PredefinedMember(PredefinedType type, string name, MemberKind kind, Func<TypeReference[]> typesBuilder, TypeReference returnType)
            : this(type, new MemberFilter(name, 0, kind, null, returnType))
		{
			filter_builder = typesBuilder;
		}

        public PredefinedMember(BuiltinTypeSpec type, string name, params TypeReference[] types)
            : this(type, MemberFilter.Method(name, 0, ParametersCompiled.CreateFullyResolved(types), null))
		{
		}

		public T Get ()
		{
			if (member != null)
				return member;

			if (declaring_type == null) {
				if (!declaring_type_predefined.Define ())
					return null;

				declaring_type = declaring_type_predefined.TypeSpec;
			}

			if (filter_builder != null) {
				var types = filter_builder ();

				if (filter.Kind == MemberKind.Field)
					filter = new MemberFilter (filter.Name, filter.Arity, filter.Kind, null, types [0]);
				else
					filter = new MemberFilter (filter.Name, filter.Arity, filter.Kind,
						ParametersCompiled.CreateFullyResolved (types), filter.MemberType);
			}

			member = MemberCache.FindMember (declaring_type, filter, BindingRestriction.DeclaredOnly) as T;
			if (member == null)
				return null;

            if (!member.IsAccessible(Compiler.currentModule))
				return null;

			return member;
		}

		public T Resolve (Location2 loc)
		{
			if (member != null)
				return member;

			if (Get () != null)
				return member;

			if (declaring_type == null) {
				if (declaring_type_predefined.Resolve () == null)
					return null;
			}

			if (filter_builder != null) {
				filter = new MemberFilter (filter.Name, filter.Arity, filter.Kind,
					ParametersCompiled.CreateFullyResolved (filter_builder ()), filter.MemberType);
			}

			string method_args = null;
			if (filter.Parameters != null)
				method_args = filter.Parameters.GetSignatureForError ();

			Compiler.Report.Error (656, loc, "The compiler required member `{0}.{1}{2}' could not be found or is inaccessible",
				declaring_type.GetSignatureForError (), filter.Name, method_args);

			return null;
		}
	}

	public class AwaiterDefinition
	{
		public PropertyReference IsCompleted { get; set; }
		public MethodReference GetResult { get; set; }
		public bool INotifyCompletion { get; set; }

		public bool IsValidPattern {
			get {
				return IsCompleted != null && GetResult != null && IsCompleted.getAccessor != null;
			}
		}
	}

	partial class TypeManager {

	static public string CSharpName(IList<TypeReference> types)
	{
		if (types.Count == 0)
			return string.Empty;

		StringBuilder sb = new StringBuilder ();
		for (int i = 0; i < types.Count; ++i) {
			if (i > 0)
				sb.Append (",");

			sb.Append (types [i].GetSignatureForError ());
		}
		return sb.ToString ();
	}

	static public string GetFullNameSignature (MemberReference mi)
	{
		return mi.GetSignatureForError ();
	}

	static public string CSharpSignature (MemberReference mb)
	{
		return mb.GetSignatureForError ();
	}
		
	public static bool IsFamilyAccessible (TypeReference type, TypeReference parent)
	{
//		TypeParameter tparam = LookupTypeParameter (type);
//		TypeParameter pparam = LookupTypeParameter (parent);

		if (type.Kind == MemberKind.TypeParameter && parent.Kind == MemberKind.TypeParameter) { // (tparam != null) && (pparam != null)) {
			if (type == parent)
				return true;

			throw new NotImplementedException ("net");
//			return tparam.IsSubclassOf (parent);
		}

		do {
			if (IsInstantiationOfSameGenericType (type, parent))
				return true;

			type = type.baseClass;
		} while (type != null);

		return false;
	}

	//
	// Checks whether `type' is a nested child of `parent'.
	//
	public static bool IsNestedChildOf (TypeReference type, ITypeDefinition parent)
	{
		if (type == null)
			return false;

		if (type.MemberDefinition2 == parent)
			return false;

		type = type.containerType;
		while (type != null) {
			if (type.MemberDefinition2 == parent)
				return true;

			type = type.containerType;
		}

		return false;
	}

	public static TypeReference GetElementType (TypeReference t)
	{
		return ((ElementTypeSpec)t).Element;
	}

	/// <summary>
	/// This method is not implemented by MS runtime for dynamic types
	/// </summary>
	public static bool HasElementType (TypeReference t)
	{
		return t is ElementTypeSpec;
	}

	/// <summary>
	///   Utility function that can be used to probe whether a type
	///   is managed or not.  
	/// </summary>
    public static bool VerifyUnmanaged(TypeReference t, Location2 loc)
	{
		if (t.IsUnmanaged)
			return true;

		while (t.IsPointer)
			t = ((ElementTypeSpec) t).Element;

		Compiler.Report.SymbolRelatedToPreviousError (t);
		Compiler.Report.Error (208, loc,
			"Cannot take the address of, get the size of, or declare a pointer to a managed type `{0}'",
			t.GetSignatureForError ());

		return false;	
	}
#region Generics
	// This method always return false for non-generic compiler,
	// while Type.IsGenericParameter is returned if it is supported.
	public static bool IsGenericParameter (TypeReference type)
	{
		return type.IsGenericParameter;
	}

	public static bool IsGenericType (TypeReference type)
	{
		return type.IsGeneric;
	}

	public static TypeReference[] GetTypeArguments (TypeReference t)
	{
		// TODO: return empty array !!
		return t.TypeArguments;
	}

	/// <summary>
	///   Check whether `type' and `parent' are both instantiations of the same
	///   generic type.  Note that we do not check the type parameters here.
	/// </summary>
	public static bool IsInstantiationOfSameGenericType (TypeReference type, TypeReference parent)
	{
		return type == parent || type.MemberDefinition2 == parent.MemberDefinition2;
	}
#endregion
}

}
